home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint112s.zoo / dosfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  31.1 KB  |  1,383 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* DOS file handling routines */
  8.  
  9. #include "mint.h"
  10.  
  11. static long do_dup P_((int,int));
  12. static void unselectme P_((PROC *));
  13.  
  14. MEMREGION *tofreed;    /* to-be-freed shared text region (set in denyshare) */
  15.  
  16. /* wait condition for selecting processes which got collisions */
  17. short select_coll;
  18.  
  19. /*
  20.  * first, some utility routines
  21.  */
  22.  
  23. FILEPTR *
  24. do_open(name, rwmode, attr, x)
  25.     const char *name;    /* file name */
  26.     int rwmode;    /* file access mode */
  27.     int attr;    /* TOS attributes for created files (if applicable) */
  28.     XATTR *x;    /* filled in with attributes of opened file */
  29. {
  30.     struct tty *tty;
  31.     fcookie dir, fc;
  32.     long devsp;
  33.     FILEPTR *f;
  34.     DEVDRV *dev;
  35.     long r;
  36.     XATTR xattr;
  37.     unsigned perm;
  38.     int creating;
  39.     char temp1[PATH_MAX];
  40.     extern FILESYS proc_filesys;
  41.  
  42. /* for special BIOS "fake" devices */
  43.     extern DEVDRV fakedev;
  44.  
  45.     TRACE(("do_open(%s)", name));
  46.  
  47. /*
  48.  * first step: get a cookie for the directory
  49.  */
  50.  
  51.     r = path2cookie(name, temp1, &dir);
  52.     if (r) {
  53.         mint_errno = (int)r;
  54.         DEBUG(("do_open(%s): error %ld", name, r));
  55.         return NULL;
  56.     }
  57.  
  58. /*
  59.  * second step: try to locate the file itself
  60.  */
  61.     r = relpath2cookie(&dir, temp1, follow_links, &fc, 0);
  62.  
  63. /*
  64.  * file found: this is an error if (O_CREAT|O_EXCL) are set
  65.  */
  66.  
  67.     if ( (r == 0) && ( (rwmode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) ) {
  68.         DEBUG(("do_open(%s): file already exists",name));
  69.         mint_errno = EACCDN;
  70.         release_cookie(&fc);
  71.         release_cookie(&dir);
  72.         return NULL;
  73.     }
  74. /*
  75.  * file not found: maybe we should create it
  76.  * note that if r != 0, the fc cookie is invalid (so we don't need to
  77.  * release it)
  78.  */
  79.     if (r == EFILNF && (rwmode & O_CREAT)) {
  80.     /* check first for write permission in the directory */
  81.         r = (*dir.fs->getxattr)(&dir, &xattr);
  82.         if (r == 0) {
  83.             if (denyaccess(&xattr, S_IWOTH))
  84.                 r = EACCDN;
  85.         }
  86.         if (r) {
  87.             DEBUG(("do_open(%s): couldn't get "
  88.                   "write permission on directory",name));
  89.             mint_errno = (int)r;
  90.             release_cookie(&dir);
  91.             return NULL;
  92.         }
  93.         r = (*dir.fs->creat)(&dir, temp1,
  94.             (S_IFREG|DEFAULT_MODE) & (~curproc->umask), attr, &fc);
  95.         if (r) {
  96.             DEBUG(("do_open(%s): error %ld while creating file",
  97.                 name, r));
  98.             mint_errno = (int)r;
  99.             release_cookie(&dir);
  100.             return NULL;
  101.         }
  102.         creating = 1;
  103.     } else if (r) {
  104.         DEBUG(("do_open(%s): error %ld while searching for file",
  105.             name, r));
  106.         mint_errno = (int)r;
  107.         release_cookie(&dir);
  108.         return NULL;
  109.     } else {
  110.         creating = 0;
  111.     }
  112.  
  113. /*
  114.  * check now for permission to actually access the file
  115.  */
  116.     r = (*fc.fs->getxattr)(&fc, &xattr);
  117.     if (r) {
  118.         DEBUG(("do_open(%s): couldn't get file attributes",name));
  119.         mint_errno = (int)r;
  120.         release_cookie(&dir);
  121.         release_cookie(&fc);
  122.         return NULL;
  123.     }
  124. /*
  125.  * we don't do directories
  126.  */
  127.     if ( (xattr.mode & S_IFMT) == S_IFDIR ) {
  128.         DEBUG(("do_open(%s): file is a directory",name));
  129.         release_cookie(&dir);
  130.         release_cookie(&fc);
  131.         mint_errno = EFILNF;
  132.         return NULL;
  133.     }
  134.  
  135.     switch (rwmode & O_RWMODE) {
  136.     case O_WRONLY:
  137.         perm = S_IWOTH;
  138.         break;
  139.     case O_RDWR:
  140.         perm = S_IROTH|S_IWOTH;
  141.         break;
  142.     case O_EXEC:
  143.         perm = (fc.fs->fsflags & FS_NOXBIT) ? S_IROTH : S_IXOTH;
  144.         break;
  145.     case O_RDONLY:
  146.         perm = S_IROTH;
  147.         break;
  148.     default:
  149.         perm = 0;
  150.         ALERT("do_open: bad file access mode: %x", rwmode);
  151.     }
  152.     if (!creating && denyaccess(&xattr, perm)) {
  153.         DEBUG(("do_open(%s): access to file denied",name));
  154.         release_cookie(&dir);
  155.         release_cookie(&fc);
  156.         mint_errno = EACCDN;
  157.         return NULL;
  158.     }
  159.  
  160. /*
  161.  * an extra check for write access -- even the superuser shouldn't
  162.  * write to files with the FA_RDONLY attribute bit set (unless,
  163.  * we just created the file, or unless the file is on the proc
  164.  * file system and hence FA_RDONLY has a different meaning)
  165.  */
  166.     if ( !creating && (xattr.attr & FA_RDONLY) && fc.fs != &proc_filesys) {
  167.         if ( (rwmode & O_RWMODE) == O_RDWR ||
  168.              (rwmode & O_RWMODE) == O_WRONLY ) {
  169.             DEBUG(("do_open(%s): can't write a read-only file",
  170.                 name));
  171.             release_cookie(&dir);
  172.             release_cookie(&fc);
  173.             mint_errno = EACCDN;
  174.             return NULL;
  175.         }
  176.     }
  177.  
  178. /*
  179.  * if writing to a setuid or setgid file, clear those bits
  180.  */
  181.     if ( (perm & S_IWOTH) && (xattr.mode & (S_ISUID|S_ISGID)) ) {
  182.         xattr.mode &= ~(S_ISUID|S_ISGID);
  183.         (*fc.fs->chmode)(&fc, (xattr.mode & ~S_IFMT));
  184.     }
  185. /*
  186.  * If the caller asked for the attributes of the opened file, copy them over.
  187.  */
  188.     if (x) *x = xattr;
  189.  
  190. /*
  191.  * So far, so good. Let's get the device driver now, and try to
  192.  * actually open the file.
  193.  */
  194.     dev = (*fc.fs->getdev)(&fc, &devsp);
  195.     if (!dev) {
  196.         mint_errno = (int)devsp;
  197.         DEBUG(("do_open(%s): device driver not found",name));
  198.         release_cookie(&dir);
  199.         release_cookie(&fc);
  200.         return NULL;
  201.     }
  202.  
  203.     if (dev == &fakedev) {        /* fake BIOS devices */
  204.         f = curproc->handle[devsp];
  205.         if (!f || f == (FILEPTR *)1) {
  206.             mint_errno = EIHNDL;
  207.             return 0;
  208.         }
  209.         f->links++;
  210.         release_cookie(&dir);
  211.         release_cookie(&fc);
  212.         return f;
  213.     }
  214.     if (0 == (f = new_fileptr())) {
  215.         release_cookie(&dir);
  216.         release_cookie(&fc);
  217.         mint_errno = ENSMEM;
  218.         return NULL;
  219.     }
  220.     f->links = 1;
  221.     f->flags = rwmode;
  222.     f->pos = 0;
  223.     f->devinfo = devsp;
  224.     f->fc = fc;
  225.     f->dev = dev;
  226.     release_cookie(&dir);
  227.  
  228.     r = (*dev->open)(f);
  229.     if (r < 0) {
  230.         DEBUG(("do_open(%s): device open failed with error %ld",
  231.             name, r));
  232.         mint_errno = (int)r;
  233.         f->links = 0;
  234.         release_cookie(&fc);
  235.         dispose_fileptr(f);
  236.         return NULL;
  237.     }
  238.  
  239.     if (tofreed) {
  240.         tofreed->links = 0;
  241.         free_region(tofreed);
  242.         tofreed = 0;
  243.     }
  244.  
  245. /* special code for opening a tty */
  246.     if (is_terminal(f)) {
  247.         extern struct tty default_tty;    /* in tty.c */
  248.  
  249.         tty = (struct tty *)f->devinfo;
  250.         tty->use_cnt++;
  251.         while (tty->hup_ospeed && !creating) {
  252.             sleep (IO_Q, (long)&tty->state);
  253.         }
  254.         /* first open for this device (not counting set_auxhandle)? */
  255.         if ((!tty->pgrp && tty->use_cnt-tty->aux_cnt <= 1) ||
  256.             tty->use_cnt <= 1) {
  257.             short s = tty->state & (TS_BLIND|TS_HOLD|TS_HPCL);
  258.             short u = tty->use_cnt, a = tty->aux_cnt;
  259.             short r = tty->rsel, w = tty->wsel;
  260.             *tty = default_tty;
  261.             if (!creating)
  262.                 tty->state = s;
  263.             if ((tty->use_cnt = u) > 1 || !creating) {
  264.                 tty->aux_cnt = a;
  265.                 tty->rsel = r, tty->wsel = w;
  266.             }
  267.             if (!(f->flags & O_HEAD)) {
  268.                 tty_ioctl(f, TIOCSTART, 0);
  269.             }
  270.         }
  271.     }
  272.     return f;
  273. }
  274.  
  275. /* 2500 ms after hangup: close device, ready for use again */
  276.  
  277. static void ARGS_ON_STACK
  278. hangup_done(p, f)
  279.     PROC *p;
  280.     FILEPTR *f;
  281. {
  282.     struct tty *tty = (struct tty *)f->devinfo;
  283.  
  284.     tty->hup_ospeed = 0;
  285.     tty->state &= ~TS_HPCL;
  286.     tty_ioctl(f, TIOCSTART, 0);
  287.     wake (IO_Q, (long)&tty->state);
  288.     tty->state &= ~TS_HPCL;
  289.     if (--f->links <= 0) {
  290.         if (--tty->use_cnt-tty->aux_cnt <= 0)
  291.             tty->pgrp = 0;
  292.         if (tty->use_cnt <= 0 && tty->xkey) {
  293.             kfree(tty->xkey);
  294.             tty->xkey = 0;
  295.         }
  296.     }
  297.  
  298. /* hack(?): the closing process may no longer exist, use pid 0 */
  299.     if ((*f->dev->close)(f, 0)) {
  300.         DEBUG(("hangup: device close failed"));
  301.     }
  302.     if (f->links <= 0) {
  303.         release_cookie(&f->fc);
  304.         dispose_fileptr(f);
  305.     }
  306. }
  307.  
  308. /* 500 ms after hangup: restore DTR */
  309.  
  310. static void ARGS_ON_STACK
  311. hangup_b1(p, f)
  312.     PROC *p;
  313.     FILEPTR *f;
  314. {
  315.     struct tty *tty = (struct tty *)f->devinfo;
  316.     TIMEOUT *t = addroottimeout(2000L, (void (*)P_((PROC *)))hangup_done, 0);
  317.  
  318.     if (tty->hup_ospeed > 0)
  319.         (*f->dev->ioctl)(f, TIOCOBAUD, &tty->hup_ospeed);
  320.     if (!t) {
  321.         /* should never happen, but... */
  322.         hangup_done(p, f);
  323.         return;
  324.     }
  325.     t->arg = (long)f;
  326.     tty->hup_ospeed = -1;
  327. }
  328.  
  329. /*
  330.  * helper function for do_close: this closes the indicated file pointer which
  331.  * is assumed to be associated with process p. The extra parameter is necessary
  332.  * because f_midipipe mucks with file pointers of other processes, so
  333.  * sometimes p != curproc.
  334.  *
  335.  * Note that the function changedrv() in filesys.c can call this routine.
  336.  * in that case, f->dev will be 0 to represent an invalid device, and
  337.  * we cannot call the device close routine.
  338.  */
  339.  
  340. long
  341. do_pclose(p, f)
  342.     PROC *p;
  343.     FILEPTR *f;
  344. {
  345.     long r = 0;
  346.  
  347.     if (!f) return EIHNDL;
  348.     if (f == (FILEPTR *)1)
  349.         return 0;
  350.  
  351. /* if this file is "select'd" by this process, unselect it
  352.  * (this is just in case we were killed by a signal)
  353.  */
  354.  
  355. /* BUG? Feature? If media change is detected while we're doing the select,
  356.  * we'll never unselect (since f->dev is set to NULL by changedrv())
  357.  */
  358.     if (f->dev) {
  359.         (*f->dev->unselect)(f, (long)p, O_RDONLY);
  360.         (*f->dev->unselect)(f, (long)p, O_WRONLY);
  361.         (*f->dev->unselect)(f, (long)p, O_RDWR);
  362.         wake (SELECT_Q, (long)&select_coll);
  363.     }
  364.  
  365.     f->links--;
  366.  
  367. /* TTY manipulation must be done *before* calling the device close routine,
  368.  * since afterwards the TTY structure may no longer exist
  369.  */
  370.     if (is_terminal(f) && f->links <= 0) {
  371.         struct tty *tty = (struct tty *)f->devinfo;
  372.         TIMEOUT *t;
  373.         long ospeed = -1L, z = 0;
  374. /* for HPCL ignore ttys open as /dev/aux, else they would never hang up */
  375.         if (tty->use_cnt-tty->aux_cnt <= 1) {
  376.             if ((tty->state & TS_HPCL) && !tty->hup_ospeed &&
  377.                 !(f->flags & O_HEAD) &&
  378.                 (*f->dev->ioctl)(f, TIOCOBAUD, &ospeed) >= 0 &&
  379.                 (t = addroottimeout(500L, (void (*)P_((PROC *)))hangup_b1, 0))) {
  380.             /* keep device open until hangup complete */
  381.                 f->links = 1;
  382.                 ++tty->use_cnt;
  383.             /* pass f to timeout function */
  384.                 t->arg = (long)f;
  385.                 (*f->dev->ioctl)(f, TIOCCBRK, 0);
  386.             /* flag: hanging up */
  387.                 tty->hup_ospeed = -1;
  388.             /* stop output, flush buffers, drop DTR... */
  389.                 tty_ioctl(f, TIOCSTOP, 0);
  390.                 tty_ioctl(f, TIOCFLUSH, 0);
  391.                 if (ospeed > 0) {
  392.                     tty->hup_ospeed = ospeed;
  393.                     (*f->dev->ioctl)(f, TIOCOBAUD, &z);
  394.                 }
  395.             } else {
  396.                 tty->pgrp = 0;
  397.             }
  398.         }
  399.         tty->use_cnt--;
  400.         if (tty->use_cnt <= 0 && tty->xkey) {
  401.             kfree(tty->xkey);
  402.             tty->xkey = 0;
  403.         }
  404.     }
  405.  
  406.     if (f->dev) {
  407.         r = (*f->dev->close)(f, p->pid);
  408.         if (r) {
  409.             DEBUG(("close: device close failed"));
  410.         }
  411.     }
  412.     if (f->links <= 0) {
  413.         release_cookie(&f->fc);
  414.         dispose_fileptr(f);
  415.     }
  416.     return  r;
  417. }
  418.  
  419. long
  420. do_close(f)
  421.     FILEPTR *f;
  422. {
  423.     return do_pclose(curproc, f);
  424. }
  425.  
  426. long ARGS_ON_STACK
  427. f_open(name, mode)
  428.     const char *name;
  429.     int mode;
  430. {
  431.     int i;
  432.     FILEPTR *f;
  433.     PROC *proc;
  434.  
  435.     TRACE(("Fopen(%s, %x)", name, mode));
  436. #if O_GLOBAL
  437.     if (mode & O_GLOBAL) {
  438.         /* oh, boy! user wants us to open a global handle! */
  439.         proc = rootproc;
  440.     }
  441.     else
  442. #endif
  443.         proc = curproc;
  444.  
  445.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  446.         if (!proc->handle[i])
  447.             goto found_for_open;
  448.     }
  449.     DEBUG(("Fopen(%s): process out of handles",name));
  450.     return ENHNDL;        /* no more handles */
  451.  
  452. found_for_open:
  453.     mode &= O_USER;        /* make sure the mode is legal */
  454.  
  455. /* note: file mode 3 is reserved for the kernel; for users, transmogrify it
  456.  * into O_RDWR (mode 2)
  457.  */
  458.     if ( (mode & O_RWMODE) == O_EXEC ) {
  459.         mode = (mode & ~O_RWMODE) | O_RDWR;
  460.     }
  461.  
  462.     proc->handle[i] = (FILEPTR *)1;    /* reserve this handle */
  463.     f = do_open(name, mode, 0, (XATTR *)0);
  464.     proc->handle[i] = (FILEPTR *)0;
  465.  
  466.     if (!f) {
  467.         return mint_errno;
  468.     }
  469.     proc->handle[i] = f;
  470. /* default is to close non-standard files on exec */
  471.     proc->fdflags[i] = FD_CLOEXEC;
  472.  
  473. #if O_GLOBAL
  474.     if (proc != curproc) {
  475.         /* we just opened a global handle */
  476.         i += 100;
  477.     }
  478. #endif
  479.  
  480.     TRACE(("Fopen: returning %d", i));
  481.     return i;
  482. }
  483.  
  484. long ARGS_ON_STACK
  485. f_create(name, attrib)
  486.     const char *name;
  487.     int attrib;
  488. {
  489.     fcookie dir;
  490.     int i;
  491.     FILEPTR *f;
  492.     long r;
  493.     PROC *proc;
  494.     int offset = 0;
  495.     char temp1[PATH_MAX];
  496.  
  497.     TRACE(("Fcreate(%s, %x)", name, attrib));
  498. #if O_GLOBAL
  499.     if (attrib & O_GLOBAL) {
  500.         proc = rootproc;
  501.         offset = 100;
  502.         attrib &= ~O_GLOBAL;
  503.     }
  504.     else
  505. #endif
  506.         proc = curproc;
  507.  
  508.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  509.         if (!proc->handle[i])
  510.             goto found_for_create;
  511.     }
  512.     DEBUG(("Fcreate(%s): process out of handles",name));
  513.     return ENHNDL;        /* no more handles */
  514.  
  515. found_for_create:
  516.     if (attrib == FA_LABEL) {
  517.         r = path2cookie(name, temp1, &dir);
  518.         if (r) return r;
  519.         r = (*dir.fs->writelabel)(&dir, temp1);
  520.         release_cookie(&dir);
  521.         if (r) return r;
  522. /*
  523.  * just in case the caller tries to do something with this handle,
  524.  * make it point to u:\dev\null
  525.  */
  526.         f = do_open("u:\\dev\\null", O_RDWR|O_CREAT|O_TRUNC, 0,
  527.                  (XATTR *)0);
  528.         proc->handle[i] = f;
  529.         proc->fdflags[i] = FD_CLOEXEC;
  530.         return i+offset;
  531.     }
  532.     if (attrib & (FA_LABEL|FA_DIR)) {
  533.         DEBUG(("Fcreate(%s,%x): illegal attributes",name,attrib));
  534.         return EACCDN;
  535.     }
  536.  
  537.     proc->handle[i] = (FILEPTR *)1;        /* reserve this handle */
  538.     f = do_open(name, O_RDWR|O_CREAT|O_TRUNC, attrib, (XATTR *)0);
  539.     proc->handle[i] = (FILEPTR *)0;
  540.  
  541.     if (!f) {
  542.         DEBUG(("Fcreate(%s) failed, error %d", name, mint_errno));
  543.         return mint_errno;
  544.     }
  545.     proc->handle[i] = f;
  546.     proc->fdflags[i] = FD_CLOEXEC;
  547.     i += offset;
  548.     TRACE(("Fcreate: returning %d", i));
  549.     return i;
  550. }
  551.  
  552. long ARGS_ON_STACK
  553. f_close(fh)
  554.     int fh;
  555. {
  556.     FILEPTR *f;
  557.     long r;
  558.     PROC *proc;
  559.  
  560.     TRACE(("Fclose: %d", fh));
  561. #if O_GLOBAL
  562.     if (fh >= 100) {
  563.         fh -= 100;
  564.         proc = rootproc;
  565.     }
  566.     else
  567. #endif
  568.         proc = curproc;
  569.  
  570.     if (fh < 0 || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  571.         return EIHNDL;
  572.     }
  573.     r = do_pclose(proc, f);
  574.  
  575. /* standard handles should be restored to default values */
  576. /* do this for TOS domain only! */
  577.     if (proc->domain == DOM_TOS) {
  578.         if (fh == 0 || fh == 1)
  579.             f = proc->handle[-1];
  580.         else if (fh == 2 || fh == 3)
  581.             f = proc->handle[-fh];
  582.         else
  583.             f = 0;
  584.     } else
  585.         f = 0;
  586.  
  587.     if (f) {
  588.         f->links++;
  589.         proc->fdflags[fh] = 0;
  590.     }
  591.     proc->handle[fh] = f;
  592.     return r;
  593. }
  594.  
  595. long ARGS_ON_STACK
  596. f_read(fh, count, buf)
  597.     int fh;
  598.     long count;
  599.     char *buf;
  600. {
  601.     FILEPTR *f;
  602.  
  603.     PROC *proc;
  604.  
  605. #if O_GLOBAL
  606.     if (fh >= 100) {
  607.         fh -= 100;
  608.         proc = rootproc;
  609.     }
  610.     else
  611. #endif
  612.         proc = curproc;
  613.  
  614.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  615.         DEBUG(("Fread: invalid handle: %d", fh));
  616.         return EIHNDL;
  617.     }
  618.     if ( (f->flags & O_RWMODE) == O_WRONLY ) {
  619.         DEBUG(("Fread: read on a write-only handle"));
  620.         return EACCDN;
  621.     }
  622.     if (is_terminal(f))
  623.         return tty_read(f, buf, count);
  624.  
  625.     TRACELOW(("Fread: %ld bytes from handle %d to %lx", count, fh, buf));
  626.     return (*f->dev->read)(f, buf, count);
  627. }
  628.  
  629. long ARGS_ON_STACK
  630. f_write(fh, count, buf)
  631.     int fh;
  632.     long count;
  633.     const char *buf;
  634. {
  635.     FILEPTR *f;
  636.     PROC *proc;
  637.     long r;
  638.  
  639. #if O_GLOBAL
  640.     if (fh >= 100) {
  641.         fh -= 100;
  642.         proc = rootproc;
  643.     }
  644.     else
  645. #endif
  646.         proc = curproc;
  647.  
  648.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  649.         DEBUG(("Fwrite: bad handle: %d", fh));
  650.         return EIHNDL;
  651.     }
  652.     if ( (f->flags & O_RWMODE) == O_RDONLY ) {
  653.         DEBUG(("Fwrite: write on a read-only handle"));
  654.         return EACCDN;
  655.     }
  656.     if (is_terminal(f))
  657.         return tty_write(f, buf, count);
  658.  
  659.     /* it would be faster to do this in the device driver, but this
  660.      * way the drivers are easier to write
  661.      */
  662.     if (f->flags & O_APPEND) {
  663.         r = (*f->dev->lseek)(f, 0L, SEEK_END);
  664.         /* ignore errors from unseekable files (e.g. pipes) */
  665.         if (r == EACCDN)
  666.             r = 0;
  667.     } else
  668.         r = 0;
  669.     if (r >= 0) {
  670.         TRACELOW(("Fwrite: %ld bytes to handle %d", count, fh));
  671.         r = (*f->dev->write)(f, buf, count);
  672.     }
  673.     if (r < 0) {
  674.         DEBUG(("Fwrite: error %ld", r));
  675.     }
  676.     return r;
  677. }
  678.  
  679. long ARGS_ON_STACK
  680. f_seek(place, fh, how)
  681.     long place;
  682.     int fh;
  683.     int how;
  684. {
  685.     FILEPTR *f;
  686.     PROC *proc;
  687.  
  688.     TRACE(("Fseek(%ld, %d) on handle %d", place, how, fh));
  689. #if O_GLOBAL
  690.     if (fh >= 100) {
  691.         fh -= 100;
  692.         proc = rootproc;
  693.     }
  694.     else
  695. #endif
  696.         proc = curproc;
  697.  
  698.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  699.         DEBUG(("Fseek: bad handle: %d", fh));
  700.         return EIHNDL;
  701.     }
  702.     if (is_terminal(f)) {
  703.         return 0;
  704.     }
  705.     return (*f->dev->lseek)(f, place, how);
  706. }
  707.  
  708. /* duplicate file pointer fh; returns a new file pointer >= min, if
  709.    one exists, or ENHNDL if not. called by f_dup and f_cntl
  710.  */
  711.  
  712. static long do_dup(fh, min)
  713.     int fh, min;
  714. {
  715.     FILEPTR *f;
  716.     int i;
  717.     PROC *proc;
  718.  
  719.     for (i = min; i < MAX_OPEN; i++) {
  720.         if (!curproc->handle[i])
  721.             goto found;
  722.     }
  723.     return ENHNDL;        /* no more handles */
  724. found:
  725. #if O_GLOBAL
  726.     if (fh >= 100) {
  727.         fh -= 100;
  728.         proc = rootproc;
  729.     } else
  730. #endif
  731.         proc = curproc;
  732.  
  733.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh]))
  734.         return EIHNDL;
  735.  
  736.     curproc->handle[i] = f;
  737.  
  738. /* set default file descriptor flags */
  739.     if (i >= 0) {
  740.         if (i >= MIN_OPEN)
  741.             curproc->fdflags[i] = FD_CLOEXEC;
  742.         else
  743.             curproc->fdflags[i] = 0;
  744.     }
  745.     f->links++;
  746.     return i;
  747. }
  748.  
  749. long ARGS_ON_STACK
  750. f_dup(fh)
  751.     int fh;
  752. {
  753.     long r;
  754.     r = do_dup(fh, MIN_OPEN);
  755.     TRACE(("Fdup(%d) -> %ld", fh, r));
  756.     return r;
  757. }
  758.  
  759. long ARGS_ON_STACK
  760. f_force(newh, oldh)
  761.     int newh;
  762.     int oldh;
  763. {
  764.     FILEPTR *f;
  765.     PROC *proc;
  766.  
  767.     TRACE(("Fforce(%d, %d)", newh, oldh));
  768.  
  769. #if O_GLOBAL
  770.     if (oldh >= 100) {
  771.         oldh -= 100;
  772.         proc = rootproc;
  773.     } else
  774. #endif
  775.         proc = curproc;
  776.  
  777.     if (oldh < MIN_HANDLE || oldh >= MAX_OPEN ||
  778.         0 == (f = proc->handle[oldh])) {
  779.         DEBUG(("Fforce: old handle invalid"));
  780.         return EIHNDL;
  781.     }
  782.  
  783.     if (newh < MIN_HANDLE || newh >= MAX_OPEN) {
  784.         DEBUG(("Fforce: new handle out of range"));
  785.         return EIHNDL;
  786.     }
  787.  
  788.     (void)do_close(curproc->handle[newh]);
  789.     curproc->handle[newh] = f;
  790.     /* set default file descriptor flags */
  791.     if (newh >= 0)
  792.         curproc->fdflags[newh] = (newh >= MIN_OPEN) ? FD_CLOEXEC : 0;
  793.     f->links++;
  794. /*
  795.  * special: for a tty, if this is becoming a control terminal and the
  796.  * tty doesn't have a pgrp yet, make it have the pgrp of the process
  797.  * doing the Fforce
  798.  */
  799.     if (is_terminal(f) && newh == -1 && !(f->flags & O_HEAD)) {
  800.         struct tty *tty = (struct tty *)f->devinfo;
  801.  
  802.         if (!tty->pgrp) {
  803.             tty->pgrp = curproc->pgrp;
  804.  
  805.             if (!(f->flags & O_NDELAY) && (tty->state & TS_BLIND))
  806.                 (*f->dev->ioctl)(f, TIOCWONLINE, 0);
  807.         }
  808.     }
  809.     return 0;
  810. }
  811.  
  812. long ARGS_ON_STACK
  813. f_datime(timeptr, fh, rwflag)
  814.     short *timeptr;
  815.     int fh;
  816.     int rwflag;
  817. {
  818.     FILEPTR *f;
  819.     PROC *proc;
  820.  
  821.     TRACE(("Fdatime(%d)", fh));
  822. #if O_GLOBAL
  823.     if (fh >= 100) {
  824.         fh -= 100;
  825.         proc = rootproc;
  826.     }
  827.     else
  828. #endif
  829.         proc = curproc;
  830.  
  831.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  832.         DEBUG(("Fdatime: invalid handle"));
  833.         return EIHNDL;
  834.     }
  835.  
  836. /* some programs use Fdatime to test for TTY devices */
  837.     if (is_terminal(f))
  838.         return EACCDN;
  839.  
  840.     return (*f->dev->datime)(f, timeptr, rwflag);
  841. }
  842.  
  843. long ARGS_ON_STACK
  844. f_lock(fh, mode, start, length)
  845.     int fh, mode;
  846.     long start, length;
  847. {
  848.     FILEPTR *f;
  849.     struct flock lock;
  850.     PROC *proc;
  851.  
  852. #if O_GLOBAL
  853.     if (fh >= 100) {
  854.         fh -= 100;
  855.         proc = rootproc;
  856.     }
  857.     else
  858. #endif
  859.         proc = curproc;
  860.  
  861.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  862.         DEBUG(("Flock: invalid handle"));
  863.         return EIHNDL;
  864.     }
  865.     TRACE(("Flock(%d,%d,%ld,%ld)", fh, mode, start, length));
  866.     lock.l_whence = SEEK_SET;
  867.     lock.l_start = start;
  868.     lock.l_len = length;
  869.  
  870.     if (mode == 0)        /* create a lock */
  871.         lock.l_type = F_WRLCK;
  872.     else if (mode == 1)    /* unlock region */
  873.         lock.l_type = F_UNLCK;
  874.     else
  875.         return EINVFN;
  876.  
  877.     return (*f->dev->ioctl)(f, F_SETLK, &lock);
  878. }
  879.  
  880. /*
  881.  * extensions to GEMDOS:
  882.  */
  883.  
  884. /*
  885.  * Fpipe(int *handles): opens a pipe. if successful, returns 0, and
  886.  * sets handles[0] to a file descriptor for the read end of the pipe
  887.  * and handles[1] to one for the write end.
  888.  */
  889.  
  890. long ARGS_ON_STACK
  891. f_pipe(usrh)
  892.     short *usrh;
  893. {
  894.     FILEPTR *in, *out;
  895.     static int pipeno = 0;
  896.     int i, j;
  897.     char pipename[32]; /* MAGIC: 32 >= strlen "u:\pipe\sys$pipe.000\0" */
  898.  
  899.     TRACE(("Fpipe"));
  900.  
  901. /* BUG: more than 999 open pipes hangs the system */
  902.     do {
  903.         ksprintf(pipename, "u:\\pipe\\sys$pipe.%03d", pipeno);
  904.         pipeno++; if (pipeno > 999) pipeno = 0;
  905.         out = do_open(pipename, O_WRONLY|O_CREAT|O_EXCL, FA_RDONLY|FA_HIDDEN|FA_CHANGED,
  906.                  (XATTR *)0);
  907.             /* read-only attribute means unidirectional fifo */
  908.             /* hidden attribute means check for broken pipes */
  909.             /* changed attribute means act like Unix fifos */
  910.     } while (out == 0 && mint_errno == EACCDN);
  911.  
  912.     if (!out) {
  913.         DEBUG(("Fpipe: error %d", mint_errno));
  914.         return mint_errno;
  915.     }
  916.  
  917.     in = do_open(pipename, O_RDONLY, 0, (XATTR *)0);
  918.     if (!in) {
  919.         DEBUG(("Fpipe: in side of pipe not opened (error %d)",
  920.             mint_errno));
  921.         (void)do_close(out);
  922.         return mint_errno;
  923.     }
  924.  
  925.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  926.         if (curproc->handle[i] == 0)
  927.             break;
  928.     }
  929.  
  930.     for (j = i+1; j < MAX_OPEN; j++) {
  931.         if (curproc->handle[j] == 0)
  932.             break;
  933.     }
  934.  
  935.     if (j >= MAX_OPEN) {
  936.         DEBUG(("Fpipe: not enough handles left"));
  937.         (void) do_close(in);
  938.         (void) do_close(out);
  939.         return ENHNDL;
  940.     }
  941.     curproc->handle[i] = in; curproc->handle[j] = out;
  942. /* leave pipes open across Pexec */
  943.     curproc->fdflags[i] = 0;
  944.     curproc->fdflags[j] = 0;
  945.  
  946.     usrh[0] = i;
  947.     usrh[1] = j;
  948.     TRACE(("Fpipe: returning 0: input %d output %d",i,j));
  949.     return 0;
  950. }
  951.  
  952. /*
  953.  * f_cntl: a combination "ioctl" and "fcntl". Some functions are
  954.  * handled here, if they apply to the file descriptors directly
  955.  * (e.g. F_DUPFD) or if they're easily translated into file system
  956.  * functions (e.g. FSTAT). Others are passed on to the device driver
  957.  * via dev->ioctl.
  958.  */
  959.  
  960. long ARGS_ON_STACK
  961. f_cntl(fh, arg, cmd)
  962.     int fh;
  963.     long arg;
  964.     int cmd;
  965. {
  966.     FILEPTR    *f;
  967.     PROC *proc;
  968.     struct flock *fl;
  969.     long r;
  970.  
  971.     TRACE(("Fcntl(%d, cmd=0x%x)", fh, cmd));
  972. #if O_GLOBAL
  973.     if (fh >= 100) {
  974.         fh -= 100;
  975.         proc = rootproc;
  976.     }
  977.     else
  978. #endif
  979.         proc = curproc;
  980.  
  981.     if (fh < MIN_HANDLE || fh >= MAX_OPEN) {
  982.         DEBUG(("Fcntl: bad file handle"));
  983.         return EIHNDL;
  984.     }
  985.  
  986.     if (cmd == F_DUPFD) {
  987. #if O_GLOBAL
  988.         if (proc != curproc) fh += 100;
  989. #endif
  990.           return do_dup(fh, (int)arg);
  991.     }
  992.  
  993.     f = proc->handle[fh];
  994.     if (!f) return EIHNDL;
  995.  
  996.     switch(cmd) {
  997.     case F_GETFD:
  998.         TRACE(("Fcntl F_GETFD"));
  999.         if (fh < 0) return EIHNDL;
  1000.         return proc->fdflags[fh];
  1001.     case F_SETFD:
  1002.         TRACE(("Fcntl F_SETFD"));
  1003.         if (fh < 0) return EIHNDL;
  1004.         proc->fdflags[fh] = arg;
  1005.         return 0;
  1006.     case F_GETFL:
  1007.         TRACE(("Fcntl F_GETFL"));
  1008.         return f->flags & O_USER;
  1009.     case F_SETFL:
  1010.         TRACE(("Fcntl F_SETFL"));
  1011.         arg &= O_USER;        /* make sure only user bits set */
  1012. #if 0
  1013.     /* COMPATIBILITY WITH OLD VERSIONS ONLY */
  1014.     /* THIS CODE WILL GO AWAY. REALLY! */
  1015.         if (arg & 4) {
  1016.             arg |= O_NDELAY;
  1017.             arg &= ~4;
  1018.         }
  1019. #endif
  1020.  
  1021.     /* make sure the file access and sharing modes are not changed */
  1022.         arg &= ~(O_RWMODE|O_SHMODE);
  1023.         arg |= f->flags & (O_RWMODE|O_SHMODE);
  1024.         f->flags &= ~O_USER;    /* set user bits to arg */
  1025.         f->flags |= arg;
  1026.         return 0;
  1027.     case FSTAT:
  1028.         return (*f->fc.fs->getxattr)(&f->fc, (XATTR *)arg);
  1029.     case F_SETLK:
  1030.     case F_SETLKW:
  1031.     /* make sure that the file was opened with appropriate permissions */
  1032.         fl = (struct flock *)arg;
  1033.         if (fl->l_type == F_RDLCK) {
  1034.             if ( (f->flags & O_RWMODE) == O_WRONLY )
  1035.                 return EACCDN;
  1036.         } else {
  1037.             if ( (f->flags & O_RWMODE) == O_RDONLY )
  1038.                 return EACCDN;
  1039.         }
  1040.         /* fall through to device ioctl */
  1041.     default:
  1042.         TRACE(("Fcntl mode %x: calling ioctl",cmd));
  1043.         if (is_terminal(f)) {
  1044.             /* tty in the middle of a hangup? */
  1045.             while (((struct tty *)f->devinfo)->hup_ospeed) {
  1046.                 sleep (IO_Q, (long)&((struct tty *)f->devinfo)->state);
  1047.             }
  1048.             if (cmd == FIONREAD || cmd == FIONWRITE ||
  1049.                 cmd == TIOCSTART || cmd == TIOCSTOP ||
  1050.                 cmd == TIOCSBRK || cmd == TIOCFLUSH) {
  1051.                 r = tty_ioctl(f, cmd, (void *)arg);
  1052.             } else {
  1053.                 r = (*f->dev->ioctl)(f, cmd, (void *)arg);
  1054.                 if (r == EINVFN) {
  1055.                     r = tty_ioctl(f, cmd, (void *)arg);
  1056.                 }
  1057.             }
  1058.         } else {
  1059.             r = (*f->dev->ioctl)(f, cmd, (void *)arg);
  1060.         }
  1061.         return r;
  1062.     }
  1063. }
  1064.  
  1065. /*
  1066.  * fselect(timeout, rfd, wfd, xfd)
  1067.  * timeout is an (unsigned) 16 bit integer giving the maximum number
  1068.  * of milliseconds to wait; rfd, wfd, and xfd are pointers to 32 bit
  1069.  * integers containing bitmasks that describe which file descriptors
  1070.  * we're interested in. These masks are changed to represent which
  1071.  * file descriptors actually have data waiting (rfd), are ready to
  1072.  * output (wfd), or have exceptional conditions (xfd). If timeout is 0,
  1073.  * fselect blocks until some file descriptor is ready; otherwise, it
  1074.  * waits only "timeout" milliseconds. Return value: number of file
  1075.  * descriptors that are available for reading/writing; or a negative
  1076.  * error number.
  1077.  */
  1078.  
  1079. /* helper function for time outs */
  1080. static void
  1081. unselectme(p)
  1082.     PROC *p;
  1083. {
  1084.     wakeselect((long)p);
  1085. }
  1086.  
  1087. long ARGS_ON_STACK
  1088. f_select(timeout, rfdp, wfdp, xfdp)
  1089.     unsigned timeout;
  1090.     long *rfdp, *wfdp, *xfdp;
  1091. {
  1092.     long rfd, wfd, xfd, col_rfd, col_wfd, col_xfd;
  1093.     long mask, bytes;
  1094.     int i, count;
  1095.     FILEPTR *f;
  1096.     PROC *p;
  1097.     TIMEOUT *t;
  1098.     int rsel;
  1099.     long wait_cond;
  1100.     short sr;
  1101.  
  1102.     if (rfdp) {
  1103.         col_rfd = rfd = *rfdp;
  1104.     }
  1105.     else
  1106.         col_rfd = rfd = 0;
  1107.  
  1108.     if (wfdp) {
  1109.         col_wfd = wfd = *wfdp;
  1110.     }
  1111.     else
  1112.         col_wfd = wfd = 0;
  1113.     if (xfdp) {
  1114.         col_xfd = xfd = *xfdp;
  1115.     } else {
  1116.         col_xfd = xfd = 0;
  1117.     }
  1118.  
  1119.     /* watch out for aliasing */
  1120.     if (rfdp) *rfdp = 0;
  1121.     if (wfdp) *wfdp = 0;
  1122.     if (xfdp) *xfdp = 0;
  1123.  
  1124.     t = 0;
  1125.  
  1126.     TRACE(("Fselect(%u, %lx, %lx, %lx)", timeout, rfd, wfd, xfd));
  1127.     p = curproc;            /* help the optimizer out */
  1128.  
  1129.     /* first, validate the masks */
  1130.     mask = 1L;
  1131.     for (i = 0; i < MAX_OPEN; i++) {
  1132.         if ( ((rfd & mask) || (wfd & mask) || (xfd & mask)) && !(p->handle[i]) ) {
  1133.             DEBUG(("Fselect: invalid handle: %d", i));
  1134.             return EIHNDL;
  1135.         }
  1136.         mask = mask << 1L;
  1137.     }
  1138.  
  1139. /* now, loop through the file descriptors, setting up the select process */
  1140. /* NOTE: wakeselect will set p->wait_cond to 0 if data arrives during the
  1141.  * selection
  1142.  * Also note: because of the validation above, we may assume that the
  1143.  * file handles are valid here. However, this assumption may no longer
  1144.  * be true after we've gone to sleep, since a signal handler may have
  1145.  * closed one of the handles.
  1146.  */
  1147.  
  1148.     curproc->wait_cond = (long)wakeselect;        /* flag */
  1149.  
  1150.  
  1151. retry_after_collision:
  1152.     mask = 1L;
  1153.     wait_cond = (long)wakeselect;
  1154.     count = 0;
  1155.     
  1156.     for (i = 0; i < MAX_OPEN; i++) {
  1157.         if (col_rfd & mask) {
  1158.             f = p->handle[i];
  1159.             if (is_terminal(f))
  1160.                 rsel = (int) tty_select(f, (long)p, O_RDONLY);
  1161.             else
  1162.                 rsel = (int) (*f->dev->select)(f, (long)p, O_RDONLY);
  1163.             switch(rsel) {
  1164.             case 0:
  1165.                 col_rfd &= ~mask;
  1166.                 break;
  1167.             case 1:
  1168.                 count++;
  1169.                 *rfdp |= mask;
  1170.                 break;
  1171.             case 2:
  1172.                 wait_cond = (long)&select_coll;
  1173.                 break;
  1174.             }
  1175.         }
  1176.         if (col_wfd & mask) {
  1177.             f = p->handle[i];
  1178.             if (is_terminal(f))
  1179.                 rsel = (int) tty_select(f, (long)p, O_WRONLY);
  1180.             else
  1181.                 rsel = (int) (*f->dev->select)(f, (long)p, O_WRONLY);
  1182.             switch(rsel) {
  1183.             case 0:
  1184.                 col_wfd &= ~mask;
  1185.                 break;
  1186.             case 1:
  1187.                 count++;
  1188.                 *wfdp |= mask;
  1189.                 break;
  1190.             case 2:
  1191.                 wait_cond = (long)&select_coll;
  1192.                 break;
  1193.             }
  1194.         }
  1195.         if (col_xfd & mask) {
  1196.             f = p->handle[i];
  1197. /* tesche: anybody worried about using O_RDWR for exceptional data? ;) */
  1198.             rsel = (*f->dev->select)(f, (long)p, O_RDWR);
  1199. /*  tesche: for old device drivers, which don't understand this
  1200.  * call, this will never be true and therefore won't disturb us here.
  1201.  */
  1202.             switch (rsel) {
  1203.             case 0:
  1204.                 col_xfd &= ~mask;
  1205.                 break;
  1206.             case 1:
  1207.                 count++;
  1208.                 *xfdp |= mask;
  1209.                 break;
  1210.             case 2:
  1211.                 wait_cond = (long)&select_coll;
  1212.                 break;
  1213.             }
  1214.         }
  1215.         mask = mask << 1L;
  1216.     }
  1217.  
  1218.     if (count == 0) {    /* no data is ready yet */
  1219.         if (timeout && !t) {
  1220.             t = addtimeout((long)timeout, unselectme);
  1221.             timeout = 0;
  1222.         }
  1223.  
  1224.     /* curproc->wait_cond changes when data arrives or the timeout happens */
  1225.         sr = spl7();
  1226.         while (curproc->wait_cond == (long)wakeselect) {
  1227.             curproc->wait_cond = wait_cond;
  1228.             spl(sr);
  1229.             /*
  1230.              * The 0x100 tells sleep() to return without sleeping
  1231.              * when curproc->wait_cond changes. This way we don't
  1232.              * need spl7 (avoiding endless serial overruns).
  1233.              * Also fixes a deadlock with checkkeys/checkbttys.
  1234.              * They are called from sleep and may wakeselect()
  1235.              * curproc. But sleep used to reset curproc->wait_cond
  1236.              * to wakeselect causing curproc to sleep forever.
  1237.              */
  1238.             if (sleep(SELECT_Q|0x100, wait_cond))
  1239.                 curproc->wait_cond = 0;
  1240.             sr = spl7();
  1241.         }
  1242.         if (curproc->wait_cond == (long)&select_coll) {
  1243.             curproc->wait_cond = (long)wakeselect;
  1244.             spl(sr);
  1245.             goto retry_after_collision;
  1246.         }
  1247.         spl(sr);
  1248.  
  1249.     /* we can cancel the time out now (if it hasn't already happened) */
  1250.         if (t) canceltimeout(t);
  1251.  
  1252.     /* OK, let's see what data arrived (if any) */
  1253.         mask = 1L;
  1254.         for (i = 0; i < MAX_OPEN; i++) {
  1255.             if (rfd & mask) {
  1256.                 f = p->handle[i];
  1257.                 if (f) {
  1258.                     bytes = 1L;
  1259.                     if (is_terminal(f))
  1260.                     (void)tty_ioctl(f, FIONREAD, &bytes);
  1261.                     else
  1262.                     (void)(*f->dev->ioctl)(f, FIONREAD,&bytes);
  1263.                     if (bytes > 0) {
  1264.                     *rfdp |= mask;
  1265.                     count++;
  1266.                     }
  1267.                 }
  1268.             }
  1269.             if (wfd & mask) {
  1270.                 f = p->handle[i];
  1271.                 if (f) {
  1272.                     bytes = 1L;
  1273.                     if (is_terminal(f))
  1274.                     (void)tty_ioctl(f, FIONWRITE, &bytes);
  1275.                     else
  1276.                         (void)(*f->dev->ioctl)(f, FIONWRITE,&bytes);
  1277.                     if (bytes > 0) {
  1278.                     *wfdp |= mask;
  1279.                     count++;
  1280.                     }
  1281.                 }
  1282.             }
  1283.             if (xfd & mask) {
  1284.                 f = p->handle[i];
  1285.                 if (f) {
  1286. /*  tesche: since old device drivers won't understand this call,
  1287.  * we set up `no exceptional condition' as default.
  1288.  */
  1289.                     bytes = 0L;
  1290.                     (void)(*f->dev->ioctl)(f, FIOEXCEPT,&bytes);
  1291.                     if (bytes > 0) {
  1292.                     *xfdp |= mask;
  1293.                     count++;
  1294.                     }
  1295.                 }
  1296.             }
  1297.             mask = mask << 1L;
  1298.         }
  1299.     } else if (t) {
  1300.         /* in case data arrived after a collsion, there
  1301.          * could be a timeout pending even if count > 0
  1302.          */
  1303.         canceltimeout(t);
  1304.     }
  1305.  
  1306.     /* at this point, we either have data or a time out */
  1307.     /* cancel all the selects */
  1308.     mask = 1L;
  1309.  
  1310.     for (i = 0; i < MAX_OPEN; i++) {
  1311.         if (rfd & mask) {
  1312.             f = p->handle[i];
  1313.             if (f)
  1314.                 (*f->dev->unselect)(f, (long)p, O_RDONLY);
  1315.         }
  1316.         if (wfd & mask) {
  1317.             f = p->handle[i];
  1318.             if (f)
  1319.                 (*f->dev->unselect)(f, (long)p, O_WRONLY);
  1320.         }
  1321.         if (xfd & mask) {
  1322.             f = p->handle[i];
  1323.             if (f)
  1324.                 (*f->dev->unselect)(f, (long)p, O_RDWR);
  1325.         }
  1326.         mask = mask << 1L;
  1327.     }
  1328.  
  1329.     /* wake other processes which got a collision */
  1330.     if (rfd || wfd || xfd)
  1331.         wake(SELECT_Q, (long)&select_coll);
  1332.  
  1333.     TRACE(("Fselect: returning %d", count));
  1334.     return count;
  1335. }
  1336.  
  1337.  
  1338. /*
  1339.  * GEMDOS extension: Fmidipipe
  1340.  * Fmidipipe(pid, in, out) manipulates the MIDI file handles (handles -4 and -5)
  1341.  * of process "pid" so that they now point to the files with handles "in" and
  1342.  * "out" in the calling process
  1343.  */
  1344.  
  1345. long ARGS_ON_STACK
  1346. f_midipipe(pid, in, out)
  1347.     int pid, in, out;
  1348. {
  1349.     PROC *p;
  1350.     FILEPTR *fin, *fout;
  1351.  
  1352. /* first, find the process */
  1353.  
  1354.     if (pid == 0)
  1355.         p = curproc;
  1356.     else {
  1357.         p = pid2proc(pid);
  1358.         if (!p)
  1359.             return EFILNF;
  1360.     }
  1361.  
  1362. /* next, validate the input and output file handles */
  1363.     if (in < MIN_HANDLE || in >= MAX_OPEN || (0==(fin = curproc->handle[in])))
  1364.         return EIHNDL;
  1365.     if ( (fin->flags & O_RWMODE) == O_WRONLY ) {
  1366.         DEBUG(("Fmidipipe: input side is write only"));
  1367.         return EACCDN;
  1368.     }
  1369.     if (out < MIN_HANDLE || out >= MAX_OPEN || (0==(fout = curproc->handle[out])))
  1370.         return EIHNDL;
  1371.     if ( (fout->flags & O_RWMODE) == O_RDONLY ) {
  1372.         DEBUG(("Fmidipipe: output side is read only"));
  1373.         return EACCDN;
  1374.     }
  1375.  
  1376. /* OK, duplicate the handles and put them in the new process */
  1377.     fin->links++; fout->links++;
  1378.     (void)do_pclose(p, p->midiin);
  1379.     (void)do_pclose(p, p->midiout);
  1380.     p->midiin = fin; p->midiout = fout;
  1381.     return 0;
  1382. }
  1383.